package com.jmxcfc.blfsc.cfca.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jmxcfc.blfsc.cfca.common.Constants;
import com.jmxcfc.blfsc.cfca.common.UuidGenerator;
import com.jmxcfc.blfsc.cfca.entity.SendDetailSub;
import com.jmxcfc.blfsc.cfca.modle.request.SealPdfRequest;
import com.jmxcfc.blfsc.cfca.modle.request.body.MultiDataBean;
import com.jmxcfc.blfsc.cfca.modle.request.body.ProofSealStrategy;
import com.jmxcfc.blfsc.cfca.modle.request.body.RequestBody;
import com.jmxcfc.blfsc.cfca.modle.request.body.SealStrategy;
import com.jmxcfc.blfsc.cfca.modle.request.head.RequestHead;
import com.jmxcfc.blfsc.cfca.modle.response.ResponseHead;
import com.jmxcfc.blfsc.cfca.modle.response.SealPdfResponse;
import com.jmxcfc.blfsc.cfca.service.ISendDetailSubService;
import com.jmxcfc.blfsc.cfca.service.ISignRequestService;
import com.jmxcfc.blfsc.cfca.util.SecurityUtils;
import com.jmxcfc.blfsc.common.common.enums.ApiStatusEnum;
import com.jmxcfc.blfsc.common.common.enums.ProcessStateEnum;
import com.jmxcfc.blfsc.common.common.request.BaseRequest;
import com.jmxcfc.blfsc.common.common.response.BaseResponse;
import com.jmxcfc.blfsc.common.common.utils.FileUtils;
import com.jmxcfc.blfsc.common.exception.*;
import com.jmxcfc.blfsc.common.sign.SignRequest;
import com.jmxcfc.blfsc.common.sign.enums.SignType;
import com.jmxcfc.blfsc.common.sign.extend.SignExtend;
import com.jmxcfc.blfsc.common.sms.BaseContext;
import com.jmxcfc.blfsc.common.validation.rule.RequestFieldRule;
import com.jmxcfc.blfsc.common.validation.rule.SignRulesUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * <p>
 * 签章签署实现类
 * </p>
 *
 * @author pbs
 * @since 2023-09-06 2:38:55
 */
@Slf4j
@Service
public class SignRequestServiceImpl implements ISignRequestService {

    /**
     * 机构编码
     */
    @Value("${com.cfca.organizationCode}")
    private String organizationCode;



    /**
     * 渠道编码
     */
    @Value("${com.cfca.channelCode}")
    private String channelCode;

    /**
     * 交易码值
     */
    @Value("${com.cfca.txCode}")
    private String txCode;

    /**
     * 请求地址(JMX搭建的无纸化系统的地址)
     */
    @Value("${com.cfca.url}")
    private String url;


    /**
     * 签章后文档保存地址的前缀
     * 真正地址格式:
     * outputFilepath/yyyyMMdd/产品/模板类型/文件名
     */
    @Value("${com.cfca.contract.outputFilepath}")
    private String outputFilepath;

    /**
     * 个人签章字体颜色
     */
    @Value("${com.cfca.contract.fontColor}")
    private String fontColor;

    /**
     * 个人签章字体样式
     */
    @Value("${com.cfca.contract.fontFamily}")
    private String fontFamily;


    /**
     * 个人签章字体大小
     */
    @Value("${com.cfca.contract.fontSize}")
    private String fontSize;

    /**
     * 个人签章文本高度
     */
    @Value("${com.cfca.contract.textHeight}")
    private String textHeight;


    /**
     * 个人签章文本宽度
     */
    @Value("${com.cfca.contract.textWidth}")
    private String textWidth;


    //签章图片显示尺寸单位毫米(如果是圆形:则为半径实际尺寸、如果是矩形:则为较长的一边的实际尺寸)
    @Value("${com.cfca.contract.displaySize}")
    private String displaySize;



    private ISendDetailSubService sendDetailSubService;
    private RestTemplate restTemplate;



    @Autowired
    public void setSendDetailSubService(ISendDetailSubService sendDetailSubService) {
        this.sendDetailSubService = sendDetailSubService;
    }

    @Autowired
    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }


    /**
     * 签章参数组织、数据入库
     * 校验:
     (1)、头部参数校验规则:业务号
     (2)、请求体参数校验:身份证、待签章pdf文件路径、产品号【暂时不校验】
     (3)、请求体扩展字段校验：
     1)签署类型校验,(1:签署个人签名企业签名、2:只签署企业签名、3:只签署个人签名)
     2)企业章规则：
     企业章账号、企业章密码、签章位置的页码(企业章)、x轴、y轴

     3)个人章规则：
     签章位置的页码(企业章)、x轴坐标、y轴坐标
     如果签署类型=1(个人+企业): 1)签署类型校验+2)企业章规则+3)个人章规则
     如果签署类型=2(只是企业章则校验):  1)签署类型校验+2)企业章规则
     如果签署类型=3(只是个人章则校验):   1)签署类型校验+3)个人章规则
     * requestNo(内部的请求流水号)不为空、
     * @param requestMessage
     * @return
     */
    @Override
    public BaseResponse<JSONObject> sendRequest(BaseRequest<SignRequest<SignExtend>> requestMessage) {
        BaseContext<String> baseContext = new BaseContext<>();
        //头部参数校验规则:业务号、请求流水号字段(CFCA(中金国信)参数serialNo单笔业务流水号)
        List<RequestFieldRule<?>> headerElementRules = baseContext.getHeaderElementRules();
        headerElementRules.add(SignRulesUtil.getRequestNoRule());

        //请求体参数校验:产品号(只是用于目录)、身份证、签章pdf文件路径、账户()
        List<RequestFieldRule<?>> bodyElementRules = baseContext.getBodyElementRules();
        bodyElementRules.add(SignRulesUtil.getAcctNameRule());
        bodyElementRules.add(SignRulesUtil.getTemplePdfPathRule());
        //bodyElementRules.add(SignRulesUtil.getProdCodeRule());
        //bodyElementRules.add(SignRulesUtil.getIdCodeRule());
        //扩展字段校验:
        List<RequestFieldRule<?>> bodyExtendElementRules = baseContext.getBodyExtendElementRules();
        //签署类型校验,(1:签署个人签名企业签名、2:只签署企业签名、3:只签署个人签名)
        bodyExtendElementRules.add(SignRulesUtil.getSignTypeRule());

        SignType signType = SignType.getEnumByType(requestMessage.getBody().getExtend().getSignType());
        log.info("签章请求业务号requestNo:{},添加业务号requestNo字段校验规则、签署类型signType字段校验规则", requestMessage.getHeader().getRequestNo());
        if (SignType.TYPE_1== signType || SignType.TYPE_2==signType) {
            //企业签章相关验证:签章(个人+企业)或者只是企业:企业章账号、企业章密码、签章位置的页码(企业章)、x轴、y轴
            bodyExtendElementRules.add(SignRulesUtil.getSealAccountRule());
            bodyExtendElementRules.add(SignRulesUtil.getSealPasswordRule());
            bodyExtendElementRules.add(SignRulesUtil.getSignPageEntRule());
            bodyExtendElementRules.add(SignRulesUtil.getSignXEntRule());
            bodyExtendElementRules.add(SignRulesUtil.getSignYEntRule());
            log.info("签章请求业务号requestNo:{},添加企业章相关校验规则:企业章账号校验、企业章密码校验、签章签署页码位置(企业章)、x轴(企业章)、y轴(企业章)", requestMessage.getHeader().getRequestNo());
       }
        if (SignType.TYPE_1== signType || SignType.TYPE_3==signType) {
            //个人章相关规则验证: 签章(个人+企业)或者只是个人:证件号码、签章位置的页码(个人章)、x轴坐标、y轴坐标
            //证件号码
            bodyElementRules.add(SignRulesUtil.getIdCodeRule());
            bodyExtendElementRules.add(SignRulesUtil.getSignPageRule());
            bodyExtendElementRules.add(SignRulesUtil.getSignXRule());
            bodyExtendElementRules.add(SignRulesUtil.getSignYRule());
            log.info("签章请求业务号requestNo:{},添加个人章相关校验规则:客户证件号、签章签署页码位置(个人章)、x轴(个人章)、y轴(个人章)", requestMessage.getHeader().getRequestNo());

        }
        return execute(requestMessage, baseContext);
    }

    /**
     * 重写扩展字段的校验:签署类型字段
     * @param body (不能传JSONObject)
     *备注:每个实现类需要自己实现该方法,然后进行扩展字段的校验
     * @param baseHandleContext
     * @param <E>
     * @throws ValidBodyException
     */
    @Override
    public <E> void validBodyExtend(SignRequest<SignExtend> body, BaseContext<E> baseHandleContext) throws ValidBodyException {
        try {
            if (Objects.nonNull(baseHandleContext)) {
                baseHandleContext.getBodyExtendElementRules().forEach(rule -> valid(rule, body.getExtend()));
            }
        } catch (RuntimeException e) {
            throw new ValidBodyException(e.getMessage());
        }
    }

    /**
     * 请求参数组装
     * 1、生成流水号(32位UUID)
     * 2、参数组合和数据sendDetailSub保存
     * 3、构造请求体
     * @param request
     * @param response
     * @param baseContext
     * @throws BeforeOutboundException
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void beforeOutbound(BaseRequest<SignRequest<SignExtend>> request, BaseResponse<JSONObject> response, BaseContext<String> baseContext) throws BeforeOutboundException {
        String requestNo = request.getHeader().getRequestNo();
        try {
            log.info("签章请求业务号requestNo:{},CFCA(中金国信)前置处理:数据落库和参数组装", requestNo);
            //32位uuid
            String serialSeq = UuidGenerator.uuid();
            log.info("签章请求业务号requestNo:{},生成的业务流水号为(32位UUID):{}", requestNo, serialSeq);
            request.getHeader().setSerialSeq(serialSeq);


            SendDetailSub sendDetailSub = new SendDetailSub();
            sendDetailSub.setRequestNo(requestNo);
            sendDetailSub.setSerialNo(serialSeq);
            sendDetailSub.setSignType(request.getBody().getExtend().getSignType());
            String requestParamStr = buildParam(request, sendDetailSub);
            //设置请求
            baseContext.setRestHttpEntity(creatRequestEntity(requestParamStr));
            //保存数据
            save(requestNo, sendDetailSub);
            log.info("签章请求业务号requestNo:{},前置处理结束", requestNo);
        } catch (Exception e) {
            log.error("签章请求业务号requestNo:{},前置处理异常:{}", requestNo, e.getMessage(), e);
            throw new BeforeOutboundException(e.getMessage(), e);
        }
    }

    /**
     * 外呼请求
     * @param request
     * @param response
     * @param baseContext
     * @throws OutboundException
     */
    @Override
    public void outbound(BaseRequest<SignRequest<SignExtend>> request, BaseResponse<JSONObject> response, BaseContext<String> baseContext) throws OutboundException {
        try{
            log.info("签章请求业务号requestNo:{},CFCA(中金国信)发送签章请求外呼,请求地址:{},请参数:{}",request.getHeader().getRequestNo(),url,baseContext.getRestHttpEntity().getBody());
            String resp = restTemplate.postForObject(url, baseContext.getRestHttpEntity(), String.class);
            log.info("签章请求业务号requestNo:{},CFCA(中金国信)发送签章请求外呼,响应内容:{}", request.getHeader().getRequestNo(), resp);
            baseContext.setRestResponse(resp);
        } catch (Exception e) {
            log.error("签章请求业务号requestNo:{},CFCA(中金国信)发送签章请求外呼异常:{}", request.getHeader().getRequestNo(), e.getMessage());
            updateWhenApiException(request.getHeader().getRequestNo(), e.getMessage());
            throw new OutboundException(e.getMessage(), e);
        }
    }




    /**
     * 后置处理
     * @param request
     * @param response
     * @param baseContext
     * @throws AfterOutboundException
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void afterOutbound(BaseRequest<SignRequest<SignExtend>> request, BaseResponse<JSONObject> response, BaseContext<String> baseContext) throws AfterOutboundException {
        String requestNo = request.getHeader().getRequestNo();
        try{
            log.info("签章请求业务号requestNo:{},后置处理:解析响应结果", requestNo);
            SendDetailSub sendDetailSub = new SendDetailSub();
            sendDetailSub.setRequestNo(requestNo);

            sendDetailSub.setApiStatus(ApiStatusEnum.SUCCESS.getStatus());
            sendDetailSub.setApiStatusDesc(ApiStatusEnum.SUCCESS.getDesc());

            /*if (StringUtils.isBlank(baseContext.getRestResponse())) {
                log.error("签章请求业务号requestNo:{},响应的结果为空", requestNo);
                response.getHeader().setProcessState(ProcessStateEnum.FAILURE);
            }*/
            SealPdfResponse sealPdfResponse = JSON.parseObject(baseContext.getRestResponse(), SealPdfResponse.class);
            ResponseHead responseHead = Optional.ofNullable(sealPdfResponse.getHead()).orElseGet(() -> new ResponseHead());
            String code = responseHead.getCode();
            String message = responseHead.getMessage();
            log.info("签章请求业务号requestNo:{},响应结果code:{},message:{}", requestNo, code, message);
           //响应码为 000000:则为成功,并返回请求结果、返回码为非 000000 时,表示错误码
            if (StringUtils.equals(Constants.CODE_000000, code)) {
                response.getHeader().setProcessState(ProcessStateEnum.SUCCESS);
                sendDetailSub.setOutputFilePath(sealPdfResponse.getBody().getOutputFilepath());
            }else {
                response.getHeader().setProcessState(ProcessStateEnum.FAILURE);
            }
            sendDetailSub.setCode(code);
            sendDetailSub.setMessage(message);
            sendDetailSub.setTransactionNo(responseHead.getTransactionNo());
            sendDetailSubService.updateById(sendDetailSub);
            response.getHeader().setResCode(code);
            response.getHeader().setResMessage(message);
            JSONObject responseBody = new JSONObject();
            responseBody.put(Constants.OUTPUT_FILE_PATH, sendDetailSub.getOutputFilePath());
            response.setBody(responseBody);

        } catch (Exception e) {
            log.error("签章请求业务号requestNo:{},后置处理异常:{}", requestNo, e.getMessage(), e);
            throw new AfterOutboundException(e.getMessage(), e);
        }
    }


    /**
     * 数据保存
     *
     * @param requestNo
     * @param sendDetailSub
     */
    private void save(String requestNo, SendDetailSub sendDetailSub) {
        try {
            sendDetailSubService.save(sendDetailSub);
        } catch (DuplicateKeyException e) {
            log.error("签章请求业务号requestNo:{},保存CFCA(中金国信)明细数据,存在重复主键Id(requestNo),违反唯一约束条件", requestNo);
            throw new RepetitionException(e);
        }
    }



    private void updateWhenApiException(String requestNo, String msg) {
        try {
            SendDetailSub sendDetailSub = new SendDetailSub();
            sendDetailSub.setRequestNo(requestNo);
            sendDetailSub.setApiStatus(ApiStatusEnum.EXCEPTION.getStatus());
            sendDetailSub.setApiStatusDesc(StringUtils.substring(msg, 0, 300));
            sendDetailSubService.updateById(sendDetailSub);
        } catch (Exception e) {
            log.error("签章外呼异常时更新数据库失败,订单号:{}", requestNo);
        }
    }

    /**
     * 参数组装
     * 签章后文档保存地址: outputFilepath/datePath/prodCode/文件名称
     备注:  其中文件名称:截取合同模板文件名称
     * @param request
     * @param sendDetailSub
     */
    private String buildParam(BaseRequest<SignRequest<SignExtend>> request, SendDetailSub sendDetailSub) throws Exception {
        //业务号
        String requestNo = request.getHeader().getRequestNo();
        //流水号
        String serialSeq = request.getHeader().getSerialSeq();

        //头部参数
        RequestHead requestHead = new RequestHead();
        requestHead.setTransactionNo(serialSeq);
        //机构编码
        requestHead.setOrganizationCode(organizationCode);
        //操作员编码(不传)
        //requestHead.setOperatorCode(operatorCode);
        //渠道编码
        requestHead.setChannelCode(channelCode);


        SignRequest<SignExtend> signRequestBody = request.getBody();

        //构造请求报文体
        RequestBody requestBody = new RequestBody();

        //inputType=1时,这边输入文件地址(todo 待签章的文件是传路径还是数据流待测试)
        requestBody.setInputSource(signRequestBody.getTemplePdfPath());
        // 输入源类型:1:pdf文件路径 、2:pdf文节流件字
        requestBody.setInputType(Constants.INPUT_TYPE_1);
        //inputType=2,填写签章pdf的文件流
        //requestBody.setPdfData();

        String localOutputFilepath = FileUtils.createOutputFilepath(outputFilepath,signRequestBody.getProdCode(),signRequestBody.getTemplePdfPath());

        log.info("签章请求业务号requestNo:{},签章后文档保存地址:{}", requestNo, localOutputFilepath);
        //文档保存地址
        requestBody.setOutputFilepath(localOutputFilepath);
        //requestBody.setOutputFilepath("/opt/nfs_share/sign/loan/contract/outputpdf/20240829/PD0003/2024082288ee0b860018ee0c58b80635_个人信息采集及使用授权书.pdf");

        //获取场景证书的方式(取值1),0:实时从CFCA CA服务申请下载场景证书、1:使用从CFCA CA服务预先申请下载并存储在本地的场景证书
        requestBody.setSceneCertChannel(Constants.SCENE_CERT_CHANNEL_1);
        //时间戳的方式(取值0),0:实时访问 CFCA 时间戳
        requestBody.setTimestampChannel(Constants.TIMESTAMP_CHANNEL_0);


        //证据信息参数
        List<MultiDataBean> multiDataBeans = generateMultiDataBeans(serialSeq);
        requestBody.setMultiDatas(multiDataBeans);

        //构造章参数:个人章、企业章、个人企业章
        SignType signType = SignType.getEnumByType(signRequestBody.getExtend().getSignType());

        if (Objects.isNull(signType)) {
            log.error("签章请求业务号requestNo:{},转换签署类型signType字段:{},异常",requestNo,signRequestBody.getExtend().getSignType());
            throw new BeforeOutboundException("转换签署类型字段signType异常");
        }
        if (SignType.TYPE_1== signType || SignType.TYPE_2==signType) {
            //签章(个人+企业)或者只是企业,
            // sendDetailSub:设置签章内容类型(1:印章绑定图片)、印章编码、印章密码、签章页码、x轴、y轴
            requestBody.setSealStrategies(generateSealStrategiesWithSeal(requestNo, serialSeq, signRequestBody,sendDetailSub));
        }

        if (SignType.TYPE_1== signType || SignType.TYPE_3==signType) {
            //签章(个人+企业)或者只是个人
            //sendDetailSub:设置:签章文本内容(客户姓名)、个人章的签章位置页码、签章Lx轴、签章Ly轴
            requestBody.setProofSealStrategies(generateProofSealStrategies(requestNo, serialSeq, signRequestBody,sendDetailSub
            ));
        }
        SealPdfRequest sealPdfRequest = new SealPdfRequest();
        //接口交易码:Tx4002
        sealPdfRequest.setTxCode(txCode);
        sealPdfRequest.setHead(requestHead);
        sealPdfRequest.setBody(requestBody);
        //设置sendDetailSub
        //签章后文档保存地址pdf地址
        sendDetailSub.setOutputFilePath(localOutputFilepath);
        generateSendDetailSub(request, requestBody, sendDetailSub);
        log.info("签章请求业务号requestNo:{},参数组织完成,参数:{}",requestNo, JSON.toJSONString(sealPdfRequest));
        return JSON.toJSONString(sealPdfRequest);
    }

    /**
     * 设置SendDetailSub的值:订单号、流水号、时间戳的方式(0:实时访问CFCA时间戳服务)、
     获取场景证书的方式(1:1:使用从CFCA 购置并在本地部署的时间戳服务器产品)
     签章客户名、证件号、证件类型(默认0:身份证)、电话号码、签章类型:2(坐标签章)、坐标值是否来源于客户端:1(客户端)
     * @param request
     * @param sendDetailSub
     */
    private void generateSendDetailSub(BaseRequest<SignRequest<SignExtend>> request,RequestBody requestBody, SendDetailSub sendDetailSub) {
        //sendDetailSub.setRequestNo(request.getHeader().getRequestNo());
        //sendDetailSub.setSerialNo(request.getHeader().getSerialSeq());
        SignRequest<SignExtend> signRequestBody = request.getBody();
        //待签章的pdf文件地址
        sendDetailSub.setPdfFilePath(signRequestBody.getTemplePdfPath());

        //sendDetailSub的值
        sendDetailSub.setInputType(requestBody.getInputType());
        //时间戳的方式
        sendDetailSub.setTimestampChannel(requestBody.getTimestampChannel());
        //获取场景证书的方式
        sendDetailSub.setSceneCertChannel(requestBody.getSceneCertChannel());




        sendDetailSub.setSealPerson(signRequestBody.getAcctName());
        sendDetailSub.setIdentificationNo(signRequestBody.getIdCode());
        //todo 证件类型默认0
        sendDetailSub.setIdentificationType(Constants.IDENTIFICATION_TYPE_0);
        sendDetailSub.setPhoneNo(signRequestBody.getPhoneNo());
        //签章类型:2:坐标签章
        sendDetailSub.setSealType(Constants.SEAL_TYP_2);
        //坐标值是否来源于客户端(取值1:来源于客户端)0是左下角、1是左上角
        sendDetailSub.setIsCenterCoordinate(Constants.IS_CENTER_COORDINATE_1);
    }


    /**
     * 构造证据信息参数
     * @return
     */
    private List<MultiDataBean>  generateMultiDataBeans(String serialSeq) throws Exception {
        MultiDataBean multiDataBean = new MultiDataBean();
        multiDataBean.setFileName("业务流水号");
        byte[] serialSeqBytes = serialSeq.getBytes(StandardCharsets.UTF_8);
        String identificationFrontDataString = Base64.encodeBase64String(serialSeqBytes);
        String identificationFrontHash = SecurityUtils.digestAndHex(serialSeqBytes);
        multiDataBean.setFileData(identificationFrontDataString);
        multiDataBean.setFileDataHash(identificationFrontHash);
        List<MultiDataBean> multiDataBeanList = new ArrayList<>();
        multiDataBeanList.add(multiDataBean);
        return multiDataBeanList;
    }

    /**
     * 构造个人章参数
     * 1、证证件类型、hash算法未确认
     * 2、sendDetailSub:设置:签章文本内容(客户姓名)、个人章的签章位置页码、签章Lx轴、签章Ly轴
     * @return
     */
    private List<ProofSealStrategy> generateProofSealStrategies(String requestNo, String serialNo, SignRequest<SignExtend> signRequest,SendDetailSub sendDetailSub
    ) {
        ProofSealStrategy proofSealStrategy = new ProofSealStrategy();
        proofSealStrategy.setSerialNo(serialNo);
        //hash算法,todo 待确认
        proofSealStrategy.setHashAlg(Constants.HASH_ALG_SHA1);
        //签名文本,
        proofSealStrategy.setSealText(signRequest.getAcctName());
        //sealText非空时,需要上传如下参数
        //文本框宽度 ，默认是100
        proofSealStrategy.setWidth(textWidth);
        //文本框高度，默认是100
        proofSealStrategy.setHeight(textHeight);
        //文本颜色值，默认黑色:000000、红色:FF0000
        //proofSealStrategy.setFontColor("FF0000");
        proofSealStrategy.setFontColor(fontColor);
        //文本字体大小，默认是12
        proofSealStrategy.setFontSize(fontSize);
        //文本字体样式,默认是宋体
        proofSealStrategy.setFamily(fontFamily);


        //keyAlg:RSA算法(默认)
        proofSealStrategy.setKeyAlg(Constants.KEY_ALG_RSA);
        //证据类型, 0:居民身份证,todo 待确认
        proofSealStrategy.setIdentificationType(Constants.IDENTIFICATION_TYPE_0);
        //证据号
        proofSealStrategy.setIdentificationNo(signRequest.getIdCode());
        //姓名
        proofSealStrategy.setSealPerson(signRequest.getAcctName());
        proofSealStrategy.setPhoneNo(signRequest.getPhoneNo());
        //sealType=2(坐标签章)
        proofSealStrategy.setSealType(Constants.SEAL_TYP_2);
        //坐标来源:0是左下角、1是左上角(1:来源客户端(值为1时,以PDF文档的左上角为原点坐标体系))
        proofSealStrategy.setIsCenterCoordinate(Constants.IS_CENTER_COORDINATE_1);
        //签章页码
        proofSealStrategy.setPageNo(signRequest.getExtend().getSignPage());
        //签章 x轴
        proofSealStrategy.setLx(signRequest.getExtend().getSignX());
        //签章 y轴
        proofSealStrategy.setLy(signRequest.getExtend().getSignY());
        List<ProofSealStrategy> proofSealStrategyList = new ArrayList<>();
        proofSealStrategyList.add(proofSealStrategy);
        //设置sendDetailSub
        sendDetailSub.setSealText(proofSealStrategy.getSealText());
        sendDetailSub.setPageNo(proofSealStrategy.getPageNo());
        sendDetailSub.setLx(proofSealStrategy.getLx());
        sendDetailSub.setLy(proofSealStrategy.getLy());

        log.info("签章请求业务号requestNo:{},构造个人签章完成,个人签章参数:{}", requestNo, JSON.toJSONString(proofSealStrategyList));
        return proofSealStrategyList;
    }

    /**
     * 构造企业章
     * sendDetailSub:设置签章内容类型(1:印章绑定图片)、印章编码、印章密码、签章页码、x轴、y轴
     * @param requestNo
     * @param serialNo
     * @param signRequest
     * @return
     */
    private List<SealStrategy> generateSealStrategiesWithSeal(String requestNo, String serialNo, SignRequest<SignExtend> signRequest,SendDetailSub sendDetailSub) {
        SealStrategy sealStrategy = new SealStrategy();
        //流水号
        sealStrategy.setSerialNo(serialNo);
        //签章内容类型,取值1:使用印章绑定图片签章
        sealStrategy.setType(Constants.TYPE_1);
        //签章编码(需要提前在CFCA控制台配置)
        sealStrategy.setSealCode(signRequest.getExtend().getSealAccount());
        //签章密码,(需要提前在CFCA控制台配置)
        sealStrategy.setSealPassword(signRequest.getExtend().getSealPassword());
        //hash算法类型 SH-1,todo 待确认
        sealStrategy.setHashAlg(Constants.HASH_ALG_SHA1);

        //签章人姓名,必填
        sealStrategy.setSealPerson(signRequest.getAcctName());

        //签章坐标
        sealStrategy.setSealType(Constants.SEAL_TYP_2);
        //坐标来源(1:来源客户端(值为1时,以PDF文档的左上角为原点坐标体系))0是左下角、1是左上角
        sealStrategy.setIsCenterCoordinate(Constants.IS_CENTER_COORDINATE_1);
        // 签章图片显示尺寸,单位毫米(非必填),默认为图片本身尺寸,签章图片显示尺寸，单位毫米；如果是圆形，则为半径实际尺寸；如果是矩形，
        // 则为较长的一边的实际尺寸；如果是不规则图形，则为较长的一边的实际尺寸
        if (StringUtils.isNotBlank(displaySize)) {
            sealStrategy.setDisplaySize(displaySize);
        }
        //签章页码
        sealStrategy.setPageNo(signRequest.getExtend().getSignPageEnt());
        //签章 x轴
        sealStrategy.setLx(signRequest.getExtend().getSignXEnt());
        //签章 y轴
        sealStrategy.setLy(signRequest.getExtend().getSignYEnt());
        List<SealStrategy> sealStrategyList = new ArrayList<>();
        sealStrategyList.add(sealStrategy);

        //设置sendDetailSub的值:签章内容类型(1:印章绑定图片)、印章编码、印章密码、签章页码、x轴、y轴
        sendDetailSub.setType(sealStrategy.getType());
        sendDetailSub.setSealCode(sealStrategy.getSealCode());
        sendDetailSub.setSealPassword(sealStrategy.getSealPassword());
        sendDetailSub.setPageNoEnt(sealStrategy.getPageNo());
        sendDetailSub.setLxEnt(sealStrategy.getLx());
        sendDetailSub.setLyEnt(sealStrategy.getLy());

        log.info("签章请求业务号requestNo:{},构造企业签章完成,企业签章参数:{}", requestNo, JSON.toJSONString(sealStrategyList));
        return sealStrategyList;

    }



    /**
     *
     * @param requestJSONString 请求参数
     * @return
     */
    private HttpEntity<String> creatRequestEntity(String requestJSONString) throws Exception {
        HttpHeaders headers = new HttpHeaders();
        byte[] requestJSONData = requestJSONString.getBytes(StandardCharsets.UTF_8);
        headers.set("jsonLength", String.valueOf( Objects.isNull(requestJSONData) ? 0 : requestJSONData.length));
        headers.setContentType(MediaType.parseMediaType(Constants.MEDIA_TYPE_APPLICATION_JSON_UTF8));
        return new HttpEntity<>(requestJSONString, headers);
    }


}
